/**
- * Get a named logger instance from the currently configured logger factory.
+ * Get the registered service provider.
*
- * @param string $channel Logger channel (name)
- * @return MWLogger
+ * If called before any service provider has been registered, it will
+ * attempt to use the $wgMWLoggerDefaultSpi global to bootstrap
+ * MWLoggerSpi registration. $wgMWLoggerDefaultSpi is expected to be an
+ * array usable by ObjectFactory::getObjectFromSpec() to create a class.
+ *
+ * @return MWLoggerSpi
+ * @see registerProvider()
+ * @see ObjectFactory::getObjectFromSpec()
*/
- public static function getInstance( $channel ) {
+ public static function getProvider() {
if ( self::$spi === null ) {
global $wgMWLoggerDefaultSpi;
$provider = ObjectFactory::getObjectFromSpec(
);
self::registerProvider( $provider );
}
+ return self::$spi;
+ }
- return self::$spi->getLogger( $channel );
+ /**
+ * Get a named logger instance from the currently configured logger factory.
+ *
+ * @param string $channel Logger channel (name)
+ * @return MWLogger
+ */
+ public static function getInstance( $channel ) {
+ return self::getProvider()->getLogger( $channel );
}
}
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+use Monolog\Handler\HandlerInterface;
+
+/**
+ * Wrapper for another HandlerInterface that will only handle a percentage of
+ * records offered to it.
+ *
+ * When HandlerInterface::handle() is called for a given record, it will be
+ * handled or ignored with a one in N chance based on the sample factor given
+ * for the handler.
+ *
+ * Usage with MWLoggerMonologSpi:
+ * @code
+ * $wgMWLoggerDefaultSpi = array(
+ * 'class' => 'MWLoggerMonologSpi',
+ * 'args' => array( array(
+ * 'handlers' => array(
+ * 'some-handler' => array( ... ),
+ * 'sampled-some-handler' => array(
+ * 'class' => 'MWLoggerMonologSamplingHandler',
+ * 'args' => array(
+ * function() {
+ * return MWLogger::getProvider()->getHandler( 'some-handler');
+ * },
+ * 2, // emit logs with a 1:2 chance
+ * ),
+ * ),
+ * ),
+ * ) ),
+ * );
+ * @endcode
+ *
+ * A sampled event stream can be useful for logging high frequency events in
+ * a production environment where you only need an idea of what is happening
+ * and are not concerned with capturing every occurence. Since the decision to
+ * handle or not handle a particular event is determined randomly, the
+ * resulting sampled log is not guaranteed to contain 1/N of the events that
+ * occurred in the application but based on [[Law of large numbers]] it will
+ * tend to be close to this ratio with a large number of attempts.
+ *
+ * @since 1.25
+ * @author Bryan Davis <bd808@wikimedia.org>
+ * @copyright © 2014 Bryan Davis and Wikimedia Foundation.
+ */
+class MWLoggerMonologSamplingHandler implements HandlerInterface {
+
+ /**
+ * @var HandlerInterface $delegate
+ */
+ protected $delegate;
+
+ /**
+ * @var int $factor
+ */
+ protected $factor;
+
+ /**
+ * @param HandlerInterface $handler Wrapped handler
+ * @param int $factor Sample factor
+ */
+ public function __construct( HandlerInterface $handler, $factor ) {
+ $this->delegate = $handler;
+ $this->factor = $factor;
+ }
+
+ public function isHandling( array $record ) {
+ return $this->delegate->isHandling( $record );
+ }
+
+ public function handle( array $record ) {
+ if ( $this->isHandling( $record )
+ && mt_rand( 1, $this->factor ) === 1
+ ) {
+ return $this->delegate->handle( $record );
+ }
+ return false;
+ }
+
+ public function handleBatch( array $records ) {
+ foreach ( $records as $record ) {
+ $this->handle( $record );
+ }
+ }
+
+ public function pushProcessor( $callback ) {
+ $this->delegate->pushProcessor( $callback );
+ return $this;
+ }
+
+ public function popProcessor() {
+ return $this->delegate->popProcessor();
+ }
+
+ public function setFormatter( FormatterInterface $formatter ) {
+ $this->delegate->setFormatter( $formatter );
+ return $this;
+ }
+
+ public function getFormatter() {
+ return $this->delegate->getFormatter();
+ }
+
+}
* @param string $name Processor name
* @return callable
*/
- protected function getProcessor( $name ) {
+ public function getProcessor( $name ) {
if ( !isset( $this->singletons['processors'][$name] ) ) {
$spec = $this->config['processors'][$name];
$processor = ObjectFactory::getObjectFromSpec( $spec );
* @param string $name Processor name
* @return \Monolog\Handler\HandlerInterface
*/
- protected function getHandler( $name ) {
+ public function getHandler( $name ) {
if ( !isset( $this->singletons['handlers'][$name] ) ) {
$spec = $this->config['handlers'][$name];
$handler = ObjectFactory::getObjectFromSpec( $spec );
* @param string $name Formatter name
* @return \Monolog\Formatter\FormatterInterface
*/
- protected function getFormatter( $name ) {
+ public function getFormatter( $name ) {
if ( !isset( $this->singletons['formatters'][$name] ) ) {
$spec = $this->config['formatters'][$name];
$formatter = ObjectFactory::getObjectFromSpec( $spec );